package com.xrui.hbase.impl;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import com.xrui.hbase.ColumnName;
import com.xrui.hbase.HBaseTable;
import com.xrui.hbase.TableReaderBuilder;
import com.xrui.hbase.schema.spec.ColumnReaderSpec;


import java.io.IOException;
import java.util.Map;

/**
 * HBase implementation of TableReaderBuilder.
 */
public final class HBaseTableReaderBuilder implements TableReaderBuilder {

    //region static

    //region Variables
    private final HBaseTable mTable;

    //endregion
    private OnDecoderCacheMiss mOnDecoderCacheMiss = null;
    private Map<ColumnName, ColumnReaderSpec> mOverrides = null;
    private Multimap<ColumnName, ColumnReaderSpec> mAlternatives = null;

    /**
     * Initialize a new HBaseTableReaderBuilder for the given HBaseTable.
     *
     * @param table HBaseTable for which to build a reader.
     */
    private HBaseTableReaderBuilder(
        final HBaseTable table
    ) {
        mTable = table;
    }
    //endregion

    //region Constructor

    /**
     * Create a new HBaseTableReaderBuilder for the given HBaseTable.
     *
     * @param table HBaseTable for which to build a reader.
     * @return a new HBaseTableReaderBuilder.
     */
    public static HBaseTableReaderBuilder create(
        final HBaseTable table
    ) {
        return new HBaseTableReaderBuilder(table);
    }
    //endregion

    //region Override TableReaderBuilder Methods

    /**
     * {@inheritDoc}
     */
    @Override
    public TableReaderBuilder withOnDecoderCacheMiss(
        final OnDecoderCacheMiss behavior
    ) {
        Preconditions.checkNotNull(behavior, "OnDecoderCacheMiss behavior may not be null.");
        Preconditions.checkState(null == mOnDecoderCacheMiss,
            "OnDecoderCacheMiss behavior already set to: %s", mOnDecoderCacheMiss);
        mOnDecoderCacheMiss = behavior;
        return this;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public OnDecoderCacheMiss getOnDecoderCacheMiss() {
        return mOnDecoderCacheMiss;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public TableReaderBuilder withColumnReaderSpecOverrides(
        final Map<ColumnName, ColumnReaderSpec> overrides
    ) {
        Preconditions.checkNotNull(overrides, "ColumnReaderSpec overrides may not be null.");
        Preconditions.checkState(null == mOverrides,
            "ColumnReaderSpec overrides already set to: %s", mOverrides);
        mOverrides = ImmutableMap.copyOf(overrides);
        return this;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Map<ColumnName, ColumnReaderSpec> getColumnReaderSpecOverrides() {
        return mOverrides;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public TableReaderBuilder withColumnReaderSpecAlternatives(
        final Multimap<ColumnName, ColumnReaderSpec> alternatives
    ) {
        Preconditions.checkNotNull(alternatives, "ColumnReaderSpec alternatives may not be null.");
        Preconditions.checkState(null == mAlternatives,
            "ColumnReaderSpec alternatives already set to: %s", mAlternatives);
        mAlternatives = ImmutableMultimap.copyOf(alternatives);
        return this;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Multimap<ColumnName, ColumnReaderSpec> getColumnReaderSpecAlternatives() {
        return mAlternatives;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public HBaseTableReader buildAndOpen() throws IOException {
        if (null == mOnDecoderCacheMiss) {
            mOnDecoderCacheMiss = DEFAULT_CACHE_MISS;
        }
        if (null == mOverrides) {
            mOverrides = DEFAULT_READER_SPEC_OVERRIDES;
        }
        if (null == mAlternatives) {
            mAlternatives = DEFAULT_READER_SPEC_ALTERNATIVES;
        }

        return HBaseTableReader.createWithOptions(
            mTable, mOnDecoderCacheMiss, mOverrides, mAlternatives);
    }
    //endregion


}
